/*
  Copyright 2012 Sergey Ostanin

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

package ru.irenproject.store;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import com.google.protobuf.ByteString;

public abstract class AbstractThing implements Thing {
  private Store fStore;
  private ByteString fId;
  private LinkedHashMap<AspectId, ByteString> fAspects = new LinkedHashMap<>();
  private LinkedHashSet<ByteString> fListenerIds = new LinkedHashSet<>();
  private boolean fIsMarkedForRender;
  private boolean fAspectsChanged;
  private boolean fListenersChanged;

  protected void initialize() {}

  final void setStore(Store store) {
    fStore = store;
  }

  @Override public final Store store() {
    return fStore;
  }

  final void setId(ByteString id) {
    fId = id;
  }

  @Override public final ByteString id() {
    return fId;
  }

  @Override public final void setAspect(AspectId aspectId, ByteString value) {
    fAspects.put(aspectId, value);
    fAspectsChanged = true;
  }

  @Override public final ByteString getAspect(AspectId aspectId) {
    return fAspects.get(aspectId);
  }

  final void addAspectsInternal(Map<AspectId, ByteString> aspects) {
    fAspects.putAll(aspects);
  }

  final Map<AspectId, ByteString> aspectMap() {
    return new LinkedHashMap<>(fAspects);
  }

  @Override public final void addListener(Thing listener) {
    addListenerId(listener.id());
  }

  @Override public final void addListenerId(ByteString id) {
    fListenerIds.add(id);
    fListenersChanged = true;
  }

  final void addListenersInternal(Collection<ByteString> listeners) {
    fListenerIds.addAll(listeners);
  }

  final List<ByteString> listenerIdList() {
    return new ArrayList<>(fListenerIds);
  }

  protected final void markForRender() {
    fIsMarkedForRender = true;
  }

  final boolean isMarkedForRender() {
    return fIsMarkedForRender;
  }

  protected final <T> T get(ByteString id, Class<T> cls) {
    return fStore.get(id, cls);
  }

  protected final void post(Event e) {
    for (ByteString listenerId : fListenerIds) {
      fStore.post(fId, listenerId, e);
    }
  }

  protected void handleEvent(Event e, Thing source) {}

  final boolean aspectsChanged() {
    return fAspectsChanged;
  }

  final boolean listenersChanged() {
    return fListenersChanged;
  }
}
